package com.xz.sanitize.strategy;

import com.fasterxml.jackson.databind.JavaType;
import com.xz.sanitize.enums.BaseEnum;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * 内置默认值规则：基本类型返回零值，引用类型返回空容器/新实例。
 */
public class BuiltinDefaultValueProvider implements DefaultValueProvider {
    @Override
    public Object defaultFor(JavaType type) {
        Class<?> raw = type.getRawClass();
        if (raw.isPrimitive()) {
            if (raw == boolean.class) return false;
            if (raw == char.class) return '\0';
            if (raw == byte.class) return (byte) 0;
            if (raw == short.class) return (short) 0;
            if (raw == int.class) return 0;
            if (raw == long.class) return 0L;
            if (raw == float.class) return 0f;
            if (raw == double.class) return 0d;
        }
        if (Number.class.isAssignableFrom(raw)) {
            if (raw == Byte.class) return (byte) 0;
            if (raw == Short.class) return (short) 0;
            if (raw == Integer.class) return 0;
            if (raw == Long.class) return 0L;
            if (raw == Float.class) return 0f;
            if (raw == Double.class) return 0d;
            if (raw == BigInteger.class) return BigInteger.ZERO;
            if (raw == BigDecimal.class) return BigDecimal.ZERO;
        }
        if (raw.isEnum() && BaseEnum.class.isAssignableFrom(raw)) {
            Object[] enumConstants = raw.getEnumConstants();
            if (enumConstants.length > 0) {
                return ((BaseEnum<?>) enumConstants[0]).defaultValue();
            }
        }
        if (raw == Boolean.class) return false;
        if (raw == Character.class) return '\0';
        if (CharSequence.class.isAssignableFrom(raw)) return "";
        if (Collection.class.isAssignableFrom(raw)) return Collections.emptyList();
        if (Map.class.isAssignableFrom(raw)) return Collections.emptyMap();
        if (Optional.class.isAssignableFrom(raw)) return Optional.empty();
        if (raw.isArray()) return java.lang.reflect.Array.newInstance(raw.getComponentType(), 0);
        return tryInstantiate(raw);
    }

    private Object tryInstantiate(Class<?> raw) {
        try {
            var ctor = raw.getDeclaredConstructor();
            ctor.setAccessible(true);
            return ctor.newInstance();
        } catch (Exception e) {
            return null;
        }
    }
}
